/*******************************************************************************
 * Copyright (c) 2006 CEA List.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     CEA List - initial API and implementation
 *******************************************************************************/
package com.cea.papyrus.core.editpart.connection;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.eclipse.draw2d.ConnectionAnchor;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.gef.ConnectionEditPart;
import org.eclipse.gef.NodeEditPart;
import org.eclipse.gef.Request;
import org.eclipse.gef.RootEditPart;
import org.eclipse.gef.editparts.AbstractGraphicalEditPart;
import org.eclipse.uml2.uml.Element;

import com.cea.papyrus.core.figures.ElementFigure;
import com.cea.papyrus.diagraminterchange2.di2.GraphConnector;
import com.cea.papyrus.diagraminterchange2.di2.GraphEdge;
import com.cea.papyrus.diagraminterchange2.di2.GraphNode;
import com.cea.papyrus.diagraminterchange2.di2.Uml1SemanticModelBridge;

/**
 * Root class of all GraphNodeEditPart.
 * This class contains utility methods and provide basic management of anchors.
 * 
 * @author dumoulin
 */
public abstract class AnchorableGraphNodeEditPart extends AbstractGraphicalEditPart implements AnchorableEditPart, NodeEditPart {
	
	/**
	 * associated anchor manager.
	 */
	protected AnchorMngr anchorMngr;
	
	/**
	 * The model tha is associated to this element is a GraphNode.
	 * 
	 * @return the GraphNode
	 */
	public GraphNode getGraphNode() {
		return (GraphNode)this.getModel();
	}
	
	/**
	 * Returns the Figure of this, as a node type figure.
	 * The default figure is a elemt node : a red rectangle
	 * 
	 * @return  Figure as a NodeFigure.
	 */
	protected ElementFigure getNodeFigure(){
		return (ElementFigure)this.createFigure() ;
	}
	
	/**
	 * Get the Bussiness Model. Throw NullPointerException if no such element.
	 * 
	 * @return 
	 * 
	 * @throws NullPointerException 
	 */
	protected Element getBussinessModel() throws NullPointerException
	{
		return  ((Uml1SemanticModelBridge)getGraphNode().getSemanticModel()).getElement();
	}
	
	/**
	 * Install EditPolicies.
	 * Here, install the anchorManager.
	 */
	protected void createEditPolicies() {
		anchorMngr = getAnchorMngr();
	}
	
	/**
	 * Get the anchor mngr. Create it if necessary.
	 * 
	 * @return 
	 */
	public AnchorMngr getAnchorMngr() {
		if(anchorMngr == null)
			anchorMngr = createAnchorManager();
		return anchorMngr;
	}
	
	/**
	 * Create the AnchorMngr.
	 * Subclasses should override this method to provide appropriate anchors manager.
	 * 
	 * @return 
	 */
	protected AnchorMngr createAnchorManager() {
		return new RectangleAnchorMngr(this);
	}
	/*
	 * 
	 */
	/**
	 * 
	 * 
	 * @return 
	 */
	protected List getModelSourceConnections() {
//		TODO Replace the next one by a view list (no list creation)
		List<GraphEdge> res = new ArrayList<GraphEdge>();
		Iterator<GraphConnector> anchors = getGraphNode().getAnchorage().iterator();
		while(anchors.hasNext())
		{
			GraphConnector anchor = anchors.next();
			Iterator<GraphEdge> edges = anchor.getGraphEdge().iterator();
			while(edges.hasNext())
			{
				GraphEdge edge = edges.next();
//				Check if this is a source anchor.
				if( edge.getAnchor().get(0)== anchor)
					res.add(edge);
			}
		}
		return res;
	}
	/*
	 * 
	 */
	/**
	 * 
	 * 
	 * @return 
	 */
	protected List getModelTargetConnections() {
//		TODO Replace the next one by a view list (no list creation)
		List<GraphEdge> res = new ArrayList<GraphEdge>();
		Iterator<GraphConnector> anchors = getGraphNode().getAnchorage().iterator();
		while(anchors.hasNext())
		{
			GraphConnector anchor = anchors.next();
			Iterator<GraphEdge> edges = anchor.getGraphEdge().iterator();
			while(edges.hasNext())
			{
				GraphEdge edge = edges.next();
//				Check if this is a source anchor.
				if( edge.getAnchor().get(1)== anchor)
					res.add(edge);
			}
		}
		return res;
	}
	
	/**
	 * 
	 * 
	 * @param connection 
	 * 
	 * @return 
	 */
	public ConnectionAnchor getSourceConnectionAnchor(ConnectionEditPart connection) {
		return getAnchorMngr().getSourceConnectionAnchor(connection);
	}
	
	/**
	 * 
	 * 
	 * @param request 
	 * 
	 * @return 
	 */
	public ConnectionAnchor getSourceConnectionAnchor(Request request) {
		return getAnchorMngr().getSourceConnectionAnchor(request);
	}
	
	/**
	 * 
	 * 
	 * @param connection 
	 * 
	 * @return 
	 */
	public ConnectionAnchor getTargetConnectionAnchor(ConnectionEditPart connection) {
		return getAnchorMngr().getTargetConnectionAnchor(connection);
	}
	
	/**
	 * 
	 * 
	 * @param request 
	 * 
	 * @return 
	 */
	public ConnectionAnchor getTargetConnectionAnchor(Request request) {
		return getAnchorMngr().getTargetConnectionAnchor(request);
	}
	
	/**
	 * Called when the model is changed.
	 * 
	 * @param notification 
	 */
	public void notifyChanged(Notification notification) {
//		How can we differenciate change kind ?
		Object feature = notification.getFeature();
		if(feature != null && feature instanceof EReference)
		{
			EReference reference = (EReference)feature;
			if( "anchorage".equals(reference.getName()) )
			{
				refreshSourceConnections();
				refreshTargetConnections();
			}
		}
	}
	
	/**
	 * Return the {@link com.cea.papyrus.diagraminterchange2.di2.Property}
	 * associated to this graph node, given its key
	 * 
	 * @param key the key of the property to find
	 * 
	 * @return <code>null</code> if the property has not been found or the
	 * value of the property if found.
	 */
	public String getProperty(String key) {
		// npe check
		if(getGraphNode() == null) {
			return null;
		}
		
		// get all properties, and check the key
		Iterator<com.cea.papyrus.diagraminterchange2.di2.Property> it = getGraphNode().getProperty().iterator();
		while (it.hasNext()) {
			com.cea.papyrus.diagraminterchange2.di2.Property property = (com.cea.papyrus.diagraminterchange2.di2.Property) it.next();
			if(property.getKey().equals(key)) {
				return property.getValue();  
			}
		}
		return null;
	}
	
	/* (non-Javadoc)
	 * @see org.eclipse.gef.editparts.AbstractGraphicalEditPart#refresh()
	 */
	/**
	 * 
	 */
	@Override
	public void refresh() {
		// add a test to check if parent is not null
		// if pareent is null, can cause some NPE in refreshVisuals
		if(getParent() != null){// && getRoot() != null) {
			super.refresh();
		}
	}
	
	/* (non-Javadoc)
	 * @see org.eclipse.gef.editparts.AbstractEditPart#getRoot()
	 */
	/**
	 * 
	 * 
	 * @return 
	 */
	@Override
	public RootEditPart getRoot() {
		if(getParent() != null) {
			return super.getRoot();
		}
		return null;
	}
}
